package com.yuanchu.order.service.impl;


import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yuanchu.common.exception.OrderException;
import com.yuanchu.common.utils.R;
import com.yuanchu.messages.service.MqMessageService;
import com.yuanchu.order.client.FeignCouponClient;
import com.yuanchu.order.client.FeignGoodsClient;
import com.yuanchu.order.client.FeignStoreClient;
import com.yuanchu.order.dao.YoshopCartDao;
import com.yuanchu.order.dto.CheckOrderDto;
import com.yuanchu.order.dto.OrderDetailDto;
import com.yuanchu.order.dto.Personal;
import com.yuanchu.order.dto.SubmitOrderParamsDto;
import com.yuanchu.order.entity.*;
import com.yuanchu.order.message.OrderMessage;
import com.yuanchu.order.searchconfig.MqOrderConstants;
import com.yuanchu.order.service.CheckoutOrderService;
import com.yuanchu.order.service.YoshopOrderAddressService;
import com.yuanchu.order.service.YoshopOrderGoodsService;
import com.yuanchu.order.service.YoshopOrderService;
import com.yuanchu.order.utils.RedisIdWorker;
import com.yuanchu.order.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;

import static com.yuanchu.order.searchconfig.PayNotifyConfig.PAYNOTIFY_EXCHANGE_TOPIC;

/**
 * @version: 1.0
 * @Author: adan
 * @description:
 * @date: 2024-02-05 14:07
 */
@Slf4j
@Service
public class CheckoutOrderServiceImpl implements CheckoutOrderService {

    @Resource
    private YoshopOrderService orderService;
    @Resource
    private YoshopCartDao cartDao;
    @Resource
    private FeignGoodsClient feignGoodsClient;

    @Resource
    private FeignStoreClient feignstoreClient;
    @Resource
    private FeignCouponClient feignCouponClient;
    @Resource
    private YoshopOrderAddressService orderAddressService;

    @Resource
    private RedisIdWorker redisIdWorker;
    @Resource
    private YoshopOrderGoodsService orderGoodsService;
    @Resource
    private RedisUtils redisUtils;

    @Resource
    CheckoutOrderService checkoutOrderService;

    @Resource
    private MqMessageService mqMessageService;

    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private RedissonClient redissonClient;
    int storeId = 10001;


    @Override
    @Transactional
    public Map<String, Object> checkoutGoodsOrderSubmit(SubmitOrderParamsDto params, Integer userId) {
        Map<String, Object> checkoutOrder = processCheckoutOrder(params, userId);
        CheckOrderDto orderDto = (CheckOrderDto) checkoutOrder.get("order");
        // 2、验库存
        if (orderDto.getHasError()) {
            throw new OrderException("很抱歉，商品 [" + orderDto.getGoodsList().get(0).getGoodsName() + "] 库存不足");
        }
        orderDto.getGoodsList().forEach(goods -> {
            if (goods.getSkuInfo().getStockNum() < goods.getTotalNum()) {
                throw new OrderException("很抱歉，商品 [" + goods.getGoodsName() + "] 库存不足");
            }
        });
        // 3、验余额、积分
        Personal personal = (Personal) checkoutOrder.get("personal");
        if (personal == null || new BigDecimal(personal.getBalance()).compareTo(new BigDecimal(orderDto.getOrderPayPrice())) < 0) {
            throw new OrderException("余额不足");
        }
        Integer isUsePoints = params.getIsUsePoints();
        if (isUsePoints != null && isUsePoints == 1 && new BigDecimal(personal.getPoints()).compareTo(new BigDecimal(orderDto.getPointsNum())) < 0) {
            throw new OrderException("积分不足");
        }

        // 4. 获取Redisson的分布式锁实例
        RLock lock = redissonClient.getLock("lock:order:" + userId);
        // 获取锁对象
        boolean isLock = lock.tryLock();
        // 加锁失败
        if (!isLock) {
            log.error("获取锁失败");
            throw new OrderException("不允许重复下单");
        }
        try {
            Integer payType = params.getPayType();
            String remark = params.getRemark();
            // 生成订单
            YoshopOrderEntity orderEntity = checkoutOrderService.createOrder(userId, params.getDelivery(), isUsePoints, payType, remark, orderDto);

            // 调用接口减少库存
            orderDto.getGoodsList().forEach(goods -> {
                R decrStockNum = feignGoodsClient.decrStockNum(goods.getGoodsId(), goods.getGoodsSkuId(), goods.getTotalNum());
                if (decrStockNum.getCode() != 200){
                    log.error("库存不足");
                    throw new OrderException("库存不足");
                }
            });

            // 支付订单
            R deductUserBalance = feignstoreClient.decrUserBalance(userId, orderEntity.getPayPrice(),
                    orderEntity.getPointsNum(), storeId);
            if (deductUserBalance.getCode() != 200){
                log.error("余额不足");
                throw new OrderException("余额不足, 支付失败");
            }

            // 7、发送订单信息
            sendOrderPayMessage(userId, params.getCouponId(), orderEntity, params.getCartIds());
            Map<String, Object> result = new HashMap<>();
            result.put("orderId", orderEntity.getOrderId());
            result.put("payType", payType);
            result.put("payment", Collections.emptyList());
            return result;
        } finally {
            // 释放锁
            lock.unlock();
        }

    }


    @Transactional
    @Override
    public Map<String, Object> checkoutOrderSubmit(SubmitOrderParamsDto params, Integer userId) {
        Map<String, Object> checkoutOrder = processCheckoutOrder(params, userId);
        CheckOrderDto orderDto = (CheckOrderDto) checkoutOrder.get("order");
        // 2、验库存
        if (orderDto.getHasError()) {
            throw new OrderException("很抱歉，商品 [" + orderDto.getGoodsList().get(0).getGoodsName() + "] 库存不足");
        }
        orderDto.getGoodsList().forEach(goods -> {
            if (goods.getSkuInfo().getStockNum() < goods.getTotalNum()) {
                throw new OrderException("很抱歉，商品 [" + goods.getGoodsName() + "] 库存不足");
            }
        });
        // 3、验余额、积分
        Personal personal = (Personal) checkoutOrder.get("personal");
        if (personal == null || new BigDecimal(personal.getBalance()).compareTo(new BigDecimal(orderDto.getOrderPayPrice())) < 0) {
            throw new OrderException("余额不足");
        }
        Integer isUsePoints = params.getIsUsePoints();
        if (isUsePoints != null && isUsePoints == 1 && new BigDecimal(personal.getPoints()).compareTo(new BigDecimal(orderDto.getPointsNum())) < 0) {
            throw new OrderException("积分不足");
        }

        // 4. 获取Redisson的分布式锁实例
        RLock lock = redissonClient.getLock("lock:order:" + userId);
        // 获取锁对象
        boolean isLock = lock.tryLock();
        // 加锁失败
        if (!isLock) {
            log.error("获取锁失败");
            throw new OrderException("不允许重复下单");
        }
        try {
            Integer payType = params.getPayType();
            String remark = params.getRemark();
            // 生成订单
            YoshopOrderEntity orderEntity = checkoutOrderService.createOrder(userId, params.getDelivery(), isUsePoints, payType, remark, orderDto);
            // 发送消息减库存
            // reduceGoodsStockNum(orderDto.getGoodsList());
            // 调用接口减少库存
            orderDto.getGoodsList().forEach(goods -> {
                R decrStockNum = feignGoodsClient.decrStockNum(goods.getGoodsId(), goods.getGoodsSkuId(), goods.getTotalNum());
                if (decrStockNum.getCode() != 200){
                    log.error("库存不足");
                    throw new OrderException("库存不足");
                }
            });

            Integer couponId = params.getCouponId();
            String cartIds = params.getCartIds();
            // 7、发送订单信息
            saveOrderPayMessage(userId, couponId, orderEntity, cartIds);

            // 8、保存订单信息到索引、redis
            setOrderCache(orderEntity.getOrderId());

            Map<String, Object> result = new HashMap<>();
            result.put("orderId", orderEntity.getOrderId());
            result.put("payType", payType);
            result.put("payment", Collections.emptyList());
            return result;
        } finally {
            // 释放锁
            lock.unlock();
        }

    }

    private void setOrderCache(Integer orderId) {
        String cacheKey = "order:" + orderId;
        OrderDetailDto orderDetail = orderService.getStoreOrderDetail(orderId, 10001);
        redisUtils.set(cacheKey, orderDetail, 60 * 60 * 24);
        rabbitTemplate.convertAndSend(MqOrderConstants.ORDER_EXCHANGE, MqOrderConstants.ORDER_INSERT_KEY, orderId);
    }

    public void sendOrderPayMessage(Integer userId, Integer couponId,
                                    YoshopOrderEntity orderEntity, String cartIds) {
        OrderMessage orderMessage = new OrderMessage();
        orderMessage.setPayPrice(orderEntity.getPayPrice());
        orderMessage.setScene(20);
        orderMessage.setStoreId(storeId);
        orderMessage.setUserId(userId);
        orderMessage.setOrderId(orderEntity.getOrderId());
        orderMessage.setOrderNo(orderEntity.getOrderNo());
        orderMessage.setCouponId(couponId);
        orderMessage.setCartIds(cartIds);
        // 发送消息队列
        notifyPayResult(JSON.toJSONString(orderMessage), Long.valueOf(orderEntity.getOrderId()), "order.*");
    }


    @Transactional
    public YoshopOrderEntity createOrder(Integer userId, String delivery, Integer isUsePoints, Integer payType, Object remark, CheckOrderDto orderDto) {
        // 生成订单
        // 3、生成订单
        YoshopOrderEntity orderEntity = checkoutOrderService.saveOrderDb(userId, delivery, payType, remark, orderDto, isUsePoints);
        // 4、订单商品表
        List<YoshopGoodsEntity> goodsList = orderDto.getGoodsList();
        checkoutOrderService.saveOrderGoodsDb(userId, orderEntity, goodsList);
        // 5、订单地址表
        YoshopUserAddressEntity address = orderDto.getAddress();
        checkoutOrderService.saveOrderAddressDb(userId, orderEntity, address);
        return orderEntity;
    }

    /**
     * 发送扣除商品库存消息
     * @param goodsList
     */
    private void reduceGoodsStockNum(List<YoshopGoodsEntity> goodsList) {
        goodsList.forEach(goods -> {
            // 6.扣减库存
            // R r = feignGoodsClient.decrStockNum(goods.getGoodsId(), goods.getSkuInfo().getGoodsSkuId(), goods.getTotalNum());
            // if (r.getCode() != 200) {
            //     log.error("扣减库存失败");
            //     throw new OrderException("扣减库存失败");
            // }
            Map<String, Object> map = new HashMap<>();
            map.put("goodsId", goods.getGoodsId());
            map.put("goodsSkuId", goods.getSkuInfo().getGoodsSkuId());
            map.put("goodsNum", goods.getTotalNum());
            // 发送消息扣减库存
            notifyPayResult(JSON.toJSONString(map), Long.valueOf(goods.getGoodsId()), "order.goods.*" );
        });
    }

    public void saveOrderPayMessage(Integer userId, Integer couponId,
                                     YoshopOrderEntity orderEntity, String cartIds) {
        OrderMessage orderMessage = new OrderMessage();
        orderMessage.setPayPrice(orderEntity.getPayPrice());
        orderMessage.setOrderPrice(orderEntity.getOrderPrice());
        orderMessage.setPointsBonus(orderEntity.getPointsBonus());
        orderMessage.setScene(20);
        orderMessage.setStoreId(storeId);
        orderMessage.setUserId(userId);
        orderMessage.setOrderId(orderEntity.getOrderId());
        orderMessage.setOrderNo(orderEntity.getOrderNo());
        orderMessage.setCouponId(couponId);
        orderMessage.setUsePoints(orderEntity.getPointsNum());
        orderMessage.setCartIds(cartIds);
        // 发送消息队列
        notifyPayResult(JSON.toJSONString(orderMessage), Long.valueOf(orderEntity.getOrderId()), "order.*");
    }

    public void notifyPayResult(String message, Long messageId, String routingKey) {
        // 设置消息持久化
        Message msgObj = MessageBuilder.withBody(message.getBytes(StandardCharsets.UTF_8))
                .setDeliveryMode(MessageDeliveryMode.PERSISTENT)
                .build();
        // 2.全局唯一的消息ID，需要封装到CorrelationData中
        CorrelationData correlationData = new CorrelationData(String.valueOf(messageId));
        // 3.添加callback
        correlationData.getFuture().addCallback(
                result -> {
                    if (result.isAck()) {
                        // 3.1.ack，消息成功
                        log.debug("通知支付结果消息发送成功, ID:{}", correlationData.getId());
                        // 删除消息表中的记录
                        mqMessageService.completed(messageId);
                    } else {
                        // 3.2.nack，消息失败
                        log.error("通知支付结果消息发送失败, ID:{}, 原因{}", correlationData.getId(), result.getReason());
                    }
                },
                ex -> log.error("消息发送异常, ID:{}, 原因{}", correlationData.getId(), ex.getMessage())
        );

        try {
            // 发送消息
            rabbitTemplate.convertAndSend(PAYNOTIFY_EXCHANGE_TOPIC, routingKey, msgObj, correlationData);
        } catch (Exception e) {
            log.error("支付成功的消息发送失败，支付单id：{}， 交易单id：{}", messageId,  e);
            // 记录消息表
            mqMessageService.addMessage("order_error", String.valueOf(messageId), message, "");
            throw new OrderException("支付成功的消息发送失败，消息id：{"+messageId+"}");
        }

    }




    @Transactional
    public void saveOrderAddressDb(Integer userId, YoshopOrderEntity orderEntity, YoshopUserAddressEntity address) {
        YoshopOrderAddressEntity orderAddress = new YoshopOrderAddressEntity();
        if (address == null) {
            throw new OrderException("创建订单异常，地址不存在");
        }
        BeanUtils.copyProperties(address, orderAddress);
        orderAddress.setUserId(userId);
        orderAddress.setStoreId(10001);
        orderAddress.setOrderId(orderEntity.getOrderId());
        orderAddress.setCreateTime(String.valueOf(System.currentTimeMillis() / 1000));
        // 订单地址保存
        boolean orderAddressSave = orderAddressService.save(orderAddress);
        if (!orderAddressSave) {
            throw new OrderException("创建订单地址异常");
        }
    }

    @Transactional
    public void saveOrderGoodsDb(Integer userId, YoshopOrderEntity orderEntity, List<YoshopGoodsEntity> goodsList) {
        if (CollectionUtils.isEmpty(goodsList)) {
            throw new OrderException("创建订单异常，商品不存在");
        }
        for (YoshopGoodsEntity goods : goodsList) {
            YoshopOrderGoodsEntity orderGoodsEntity = new YoshopOrderGoodsEntity();
            BeanUtils.copyProperties(goods, orderGoodsEntity);
            Integer imageId = goods.getSkuInfo().getImageId();
            if (imageId == null || imageId == 0) {
                Integer image = feignGoodsClient.queryGoodsImage(goods.getGoodsId());
                orderGoodsEntity.setImageId(image);
            }
            orderGoodsEntity.setImageId(imageId);
            // List<Map<String, Object>> goodsProps = goods.getSkuInfo().getGoodsProps();
            orderGoodsEntity.setOrderId(orderEntity.getOrderId());
            List<Map<String, Object>> goodsProps = goods.getSkuInfo().getGoodsProps();
            orderGoodsEntity.setGoodsProps(JSON.toJSONString(goodsProps));

            orderGoodsEntity.setLinePrice(goods.getSkuInfo().getLinePrice());
            orderGoodsEntity.setGoodsWeight(goods.getSkuInfo().getGoodsWeight());
            orderGoodsEntity.setGradeRatio(String.valueOf(goods.getGradeRatio()));
            orderGoodsEntity.setCouponMoney(String.valueOf(goods.getCouponMoney()));
            orderGoodsEntity.setPointsBonus(Integer.valueOf(goods.getPointsBonus()));
            orderGoodsEntity.setIsUserGrade(goods.getIsUserGrade() ? 1 : 0);
            orderGoodsEntity.setUserId(userId);
            orderGoodsEntity.setStoreId(10001);
            orderGoodsEntity.setCreateTime(String.valueOf(System.currentTimeMillis() / 1000));
            orderGoodsEntity.setContent("");
            // 订单商品保存
            boolean orderGoodsSave = orderGoodsService.save(orderGoodsEntity);
            if (!orderGoodsSave) {
                throw new OrderException("创建商品订单异常");
            }
        }
    }

    @Transactional
    public YoshopOrderEntity saveOrderDb(Integer userId, String delivery, Integer payType,
                                         Object remark, CheckOrderDto orderDto, Integer isUsePoints) {
        YoshopOrderEntity orderEntity = new YoshopOrderEntity();

        BeanUtils.copyProperties(orderDto, orderEntity);
        orderEntity.setUserId(userId);
        // 订单id
        long orderNo = redisIdWorker.nextId("order");
        orderEntity.setPayPrice(orderDto.getOrderPayPrice());
        // 订单号
        orderEntity.setOrderNo(String.valueOf(orderNo));
        // 订单总价格（优惠前）
        orderEntity.setTotalPrice(orderDto.getOrderTotalPrice());
        // 订单价格 （优惠后）
        orderEntity.setOrderPrice(orderDto.getOrderPrice());
        // 买家留言
        if (remark != null) {
            orderEntity.setBuyerRemark(remark.toString());
        }
        // 支付状态
        orderEntity.setPayStatus(20);
        orderEntity.setPayTime(String.valueOf(Instant.now().toEpochMilli() / 1000));
        // 配送方式
        orderEntity.setDeliveryType(Integer.valueOf(delivery));
        // 来源客户端
        orderEntity.setPlatform("MP-WEIXIN");
        // 店铺id
        orderEntity.setStoreId(10001);
        orderEntity.setCreateTime(String.valueOf(System.currentTimeMillis() / 1000));
        orderEntity.setUpdateTime(String.valueOf(System.currentTimeMillis() / 1000));
        orderEntity.setPayType(payType);
        // 测试添加订单
        orderEntity.setOrderId(11);
        if (isUsePoints == 0) {
            orderEntity.setPointsNum(0);
            orderEntity.setPointsMoney("0");
        }
        // 添加订单表
        boolean orderSave = orderService.save(orderEntity);
        if (!orderSave) {
            log.error("创建订单异常");
            throw new OrderException("创建订单异常");
        }
        return orderEntity;
    }



    @Override
    public Map<String, Object> processCheckoutOrder(SubmitOrderParamsDto params, Integer userId) {
        String mode = params.getMode();
        String delivery = params.getDelivery();
        Integer couponId = params.getCouponId();
        Integer isUsePoints = params.getIsUsePoints();
        if ("cart".equals(mode)) {
            // 获取购物车id
            String cartIds = params.getCartIds();
            // 根据cartIds获取商品信息
            List<YoshopCartEntity> goodsCarts = queryGoodsByCartIds(cartIds);
            return checkOutOrderGoods(userId, couponId, Integer.valueOf(delivery), isUsePoints, goodsCarts);
        }
        String goodsId = params.getGoodsId();
        String goodsSkuId = params.getGoodsSkuId();
        String goodsNum = params.getGoodsNum();
        List<YoshopCartEntity> goodsCarts = new ArrayList<>();
        YoshopCartEntity carts = new YoshopCartEntity();
        carts.setGoodsId(Integer.valueOf(goodsId));
        carts.setGoodsSkuId(goodsSkuId);
        carts.setGoodsNum(Integer.valueOf(goodsNum));
        goodsCarts.add(carts);
        return checkOutOrderGoods(userId, couponId, Integer.valueOf(delivery), isUsePoints, goodsCarts);
    }

    @Override
    public Map<String, Object> checkoutOrder(Map<String, Object> params, Integer userId){
        SubmitOrderParamsDto paramsDto = new SubmitOrderParamsDto();
        // 获取下单方式
        String mode = (String) params.get("mode");
        // 获取配送方式
        String delivery = params.get("delivery").toString();
        // 获取优惠券id
        Integer couponId = Integer.valueOf(params.get("couponId").toString());
        // 获取是否使用积分
        Integer isUsePoints = Integer.valueOf(params.get("isUsePoints").toString());

        if ("buyNow".equals(mode)){
            // 获取商品id
            String goodsId = params.get("goodsId").toString();
            // 获取商品数量
            String goodsSkuId = params.get("goodsSkuId").toString();
            // 获取商品skuId
            String goodsNum = params.get("goodsNum").toString();
            paramsDto.setGoodsId(goodsId);
            paramsDto.setGoodsSkuId(goodsSkuId);
            paramsDto.setGoodsNum(goodsNum);
        }else {
            // 获取购物车id
            String cartIds = params.get("cartIds").toString();
            paramsDto.setCartIds(cartIds);
        }
        paramsDto.setMode(mode);
        paramsDto.setDelivery(delivery);
        paramsDto.setCouponId(couponId);
        paramsDto.setIsUsePoints(isUsePoints);
        return processCheckoutOrder(paramsDto, userId);
    }

    private static Map<String, Object> getOrderSetting(Map pointMap) {
        String pointsName = (String) pointMap.get("points_name");
        String describe = (String) pointMap.get("describe");
        int[] deliveryType = new int[]{10};
        Map<String, Object> setting = new HashMap<>();
        setting.put("points_name", pointsName);
        setting.put("points_describe", describe);
        setting.put("delivery_type", deliveryType);
        return setting;
    }

    private static BigDecimal pointsDeduction(YoshopGoodsEntity goodsEntity, Map pointMap, BigDecimal gradePrice, Integer userPoints) {
        BigDecimal pointsMoney = BigDecimal.ZERO;
        Integer isPointsDiscount = goodsEntity.getIsPointsDiscount();
        if (isPointsDiscount == 1) {
            // 系统是否开启积分抵扣
            Integer isShoppingDiscount = (Integer) pointMap.get("is_shopping_discount");
            if (isShoppingDiscount == 1) {
                if (StringUtils.isEmpty(goodsEntity.getPointsDiscountConfig())) {
                    // 获取默认积分抵扣规则 YoshopGoodsEntity goodsEntity, BigDecimal goodsPrice,
                    pointsMoney = getPointsDeductionPrice(pointMap, gradePrice, userPoints);
                } else {
                    // 设置自定义积分抵扣价格
                }
            }
        } else {
            // 未开启积分抵扣
            goodsEntity.setTotalPayPrice(String.valueOf(gradePrice));
        }
        return pointsMoney;
    }

    public Map<String, Object> checkOutOrderGoods(Integer userId, Integer couponId, Integer delivery,
                                                  Integer isUsePoints, List<YoshopCartEntity> goodsCarts) {

        CheckOrderDto order = new CheckOrderDto();
        // 获取用户信息
        YoshopUserEntity user = feignstoreClient.queryUserByUserId(userId);

        // 获取用户默认地址id
        Integer addressId = user.getAddressId();
        // balance 用户余额
        String balance = user.getBalance();
        // 获取用户默认地址
        YoshopUserAddressEntity address = feignstoreClient.queryUserDefaultAddress(userId, addressId);
        // 用户默认地址是否存在
        order.setExistAddress(address != null);
        order.setAddress(address);
        order.setPointsBonus(0);
        // 获取用户会员等级
        YoshopUserGradeEntity userGrade = feignstoreClient.queryUserGrade(user.getGradeId());
        // 获取订单费用信息
        BigDecimal orderPayPrice = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
        BigDecimal orderTotalPrice = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
        int orderTotalNum = 0;
        // 积分奖励
        BigDecimal pointsMoney = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
        // 获取默认积分规则
        String pointData = feignstoreClient.queryPointData();
        Map pointMap = JSON.parseObject(pointData, Map.class);
        // 商品运费
        BigDecimal goodsExpress = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
        boolean expressFlag = false;
        // 奖励积分
        int pointsBonus = 0;
        // 构建商品订单信息
        List<YoshopGoodsEntity> goodsList = new ArrayList<>();
        for (YoshopCartEntity goodsCart : goodsCarts) {
            Integer goodsNum = goodsCart.getGoodsNum();
            orderTotalNum += goodsNum;
            Integer goodsId = goodsCart.getGoodsId();
            String goodsSkuId = goodsCart.getGoodsSkuId();
            // 根据goodsId获取商品信息
            YoshopGoodsEntity goodsEntity = feignGoodsClient.queryGoodsInfo(goodsId, goodsSkuId);
            //  判断商品库存
            if (goodsEntity == null || goodsNum > goodsEntity.getSkuInfo().getStockNum()) {
                order.setHasError(true);
                order.setErrorMsg("很抱歉, [" + goodsEntity.getGoodsName() + "]目前库存数量不足，请重新选择");
            }
            Integer userPoints = user.getPoints();

            YoshopGoodsEntity goods = setGoodsInfo(goodsEntity, goodsNum, String.valueOf(address.getCityId()), userGrade, goodsSkuId, userPoints, pointMap);
            pointsBonus += Integer.valueOf(goods.getPointsBonus());
            orderTotalPrice = orderTotalPrice.add(new BigDecimal(goods.getTotalPayPrice()));
            String expressPrice = goodsEntity.getExpressPrice();
            goodsExpress = goodsExpress.add(new BigDecimal(expressPrice));
            if (Double.parseDouble(expressPrice) <= 0) {
                expressFlag = true;
            }
            if (!goods.getIsIntraRegion()) {
                // 不再配送区域
                order.setHasError(true);
                order.setIsIntraRegion(false);
                order.setErrorMsg("该商品[" + goods.getGoodsName() + "]不在配送区域");
            }
            goodsList.add(goods);
        }

        if (expressFlag) {
            goodsExpress = new BigDecimal("0.00");
        }
        order.setExpressPrice(String.valueOf(goodsExpress)); // 运费价格
        // 是否开启积分抵扣
        pointsMoney = setOrderPointsDiscount(pointsMoney, order, user, orderTotalPrice, pointMap);
        if (pointsMoney.compareTo(BigDecimal.ZERO) > 0) {
            order.setIsAllowPoints(true);
        }

        // 设置订单商品信息
        order.setGoodsList(goodsList);

        // 设置订单配送方式（10 快递）
        order.setDelivery("10");

        // 获取优惠券信息
        List<YoshopUserCouponEntity> coupons = feignCouponClient.queryUserCoupon(0, userId);
        List<YoshopUserCouponEntity> couponList = new ArrayList<>();

        if (!CollectionUtils.isEmpty(coupons)) {
            couponList = setOrderCoupons(couponId, order, orderTotalPrice, coupons, couponList);
        } else {
            order.setCouponMoney("0.00");
        }

        order.setCouponId(couponId);
        order.setCouponList(couponList);

        // 设置是否使用积分
        order.setIsUsePoints(String.valueOf(isUsePoints));
        if (isUsePoints == 1) {
            orderTotalPrice = orderTotalPrice.subtract(pointsMoney);
            // 奖励积分
            pointsBonus = pointsBonus - pointsMoney.intValue();
        }
        order.setPointsMoney(String.valueOf(pointsMoney));
        order.setPointsNum(pointsMoney.intValue());
        order.setPointsBonus(pointsBonus - order.getPointsBonus());
        order.setOrderTotalPrice(String.valueOf(orderTotalPrice));
        // 设置订单价格(不含运费)
        order.setOrderPrice(String.valueOf(orderTotalPrice));
        order.setOrderTotalNum(orderTotalNum);
        // 设置订单支付总价格(含运费)
        orderPayPrice = orderTotalPrice.subtract(new BigDecimal(order.getCouponMoney())).add(goodsExpress);
        order.setOrderPayPrice(String.valueOf(orderPayPrice));
        // 设置支付类型
        order.setPayType(10);


        // setting部分
        Map<String, Object> setting = getOrderSetting(pointMap);
        order.setSetting(setting);

        // personan
        Personal personal = getPersonal(userId, user, addressId, balance);
        Map<String, Object> map = new HashMap<>();
        map.put("order", order);
        map.put("personal", personal);
        map.put("setting", setting);

        return map;
    }

    private static Personal getPersonal(Integer userId, YoshopUserEntity user, Integer addressId, String balance) {
        Personal personal = new Personal();
        personal.setUserId(userId);
        personal.setAddressId(addressId);
        personal.setBalance(balance.toString());
        personal.setPoints(user.getPoints());
        return personal;
    }

    /**
     * 获取积分赠送数量
     *
     * @param pointMap
     * @param goodsPayPrice
     * @return
     */
    public int GetPointsBonus(Map pointMap, BigDecimal goodsPayPrice) {
        // 积分赠送比例 (设置1个积分可赠送0.1元，则10积分可赠送1元，100积分可赠送10元)%
        String giftRatio = (String) pointMap.get("gift_ratio");
        // 创建一个表示10%的BigDecimal对象，这里需要指定精度，因为0.1无法精确表示为二进制小数
        // 将值除以100
        BigDecimal value = new BigDecimal(giftRatio);
        BigDecimal maxGiftRadio = value.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
        // 最大赠送积分数量
        BigDecimal pointsMoneyNum = goodsPayPrice.multiply(maxGiftRadio).setScale(2, RoundingMode.HALF_UP);
        return pointsMoneyNum.toBigInteger().intValue();
    }

    private static BigDecimal memberPrice(YoshopUserGradeEntity userGrade, Integer goodsNum, YoshopGoodsEntity goodsEntity, BigDecimal goodsPrice) {
        BigDecimal goodsPayPrice;
        // 会员价格
        String equity = userGrade.getEquity();
        Map map = JSON.parseObject(equity, Map.class);
        String gradeRatio = (String) map.get("discount");   // 9.7折
        goodsEntity.setGradeRatio(Double.valueOf(gradeRatio));
        // 会员折扣价格（原价*97%=现价）
        BigDecimal gradePriceGoods = goodsPrice.multiply(new BigDecimal(gradeRatio)).multiply(new BigDecimal("0.1"))
                .setScale(2, RoundingMode.HALF_UP);
        goodsEntity.setGradeGoodsPrice(String.valueOf(gradePriceGoods));
        // 会员优惠的金额（商品原价 - 会员价格）
        BigDecimal gradeTotalPrice = goodsPrice.subtract(gradePriceGoods);
        goodsEntity.setGradeTotalMoney(String.valueOf(gradeTotalPrice));

        goodsPayPrice = gradePriceGoods.multiply(BigDecimal.valueOf(goodsNum)).setScale(2, RoundingMode.HALF_UP);
        return goodsPayPrice;
    }

    private static BigDecimal nonMemberPrice(Integer goodsNum, YoshopGoodsEntity goodsEntity, BigDecimal goodsPrice) {
        // 非会员价格
        BigDecimal goodsPayPrice = goodsPrice.multiply(BigDecimal.valueOf(goodsNum)).setScale(2, RoundingMode.HALF_UP);
        goodsEntity.setGradeRatio(Double.valueOf("0"));
        goodsEntity.setGradeGoodsPrice(String.valueOf(goodsPrice));
        goodsEntity.setGradeTotalMoney("0");

        return goodsPayPrice;
    }

    private List<YoshopUserCouponEntity> setOrderCoupons(Integer couponId, CheckOrderDto order, BigDecimal orderTotalPrice, List<YoshopUserCouponEntity> coupons, List<YoshopUserCouponEntity> couponList) {
        List<YoshopUserCouponEntity> couponEntityList = new ArrayList<>();
        if (StringUtils.isEmpty(couponId) || couponId == 0) {
            order.setCouponMoney("0.00");
            order.setPointsBonus(0);
        }
        for (YoshopUserCouponEntity coupon : coupons) {
            coupon.setIsApply(true);
            if (!StringUtils.isEmpty(couponId) && couponId != 0 && coupon.getCouponId().equals(couponId)) {
                order.setCouponMoney(String.valueOf(coupon.getReducePrice()));
                order.setPointsBonus(new BigDecimal(coupon.getReducePrice()).intValue());
            }
            // 设置优惠券类型
            Integer couponType = coupon.getCouponType();
            if (couponType == 20 || (couponType == 10 && orderTotalPrice.compareTo(new BigDecimal(coupon.getMinPrice())) >= 0)) {
                couponEntityList.add(coupon);
            }
        }
        return couponEntityList;
    }

    /**
     * 判断是否在包邮区域内
     *
     * @param region   可配送区域(城市id集)
     * @param regionId 地址id
     * @return
     */
    private boolean isIntraRegion(String region, Integer regionId) {
        ObjectMapper mapper = new ObjectMapper(); // 创建一个ObjectMapper对象
        List<Integer> regionIds = null;
        try {
            regionIds = mapper.readValue(region, new TypeReference<List<Integer>>() {
            });
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }

        return regionIds.contains(regionId);
    }

    private static BigDecimal getPointsDeductionPrice(Map pointMap, BigDecimal gradePrice, Integer userPoints) {
        // 设置积分抵扣价格  getPointsDeductionPrice
        // 积分抵扣比例 (设置1个积分可抵扣0.1元，则10积分可抵扣1元，100积分可抵扣10元)
        // String discountRatio = (String) pointMap.get("discount_ratio");
        Object discount = pointMap.get("discount");
        Map map = JSON.parseObject(discount.toString(), Map.class);
        Object discountRatio = map.get("discount_ratio");
        // 满减金额
        Object fullOrderPrice = map.get("full_order_price");
        // 最大抵扣金额比例
        Object maxOrderPrice = map.get("max_money_ratio");

        // 计算抵扣金额
        if (userPoints > 0 && gradePrice.compareTo(new BigDecimal(fullOrderPrice.toString())) > 0) {
            // 用户最大抵扣金额   =  （积分 * 10%）
            BigDecimal pointsMoney = new BigDecimal(discountRatio.toString()).multiply(new BigDecimal(userPoints)).setScale(2, RoundingMode.HALF_UP);
            // 判断抵扣金额是否大于用户最大抵扣金额
            // 创建一个表示10%的BigDecimal对象，这里需要指定精度，因为0.1无法精确表示为二进制小数
            // 将值除以100
            BigDecimal value = new BigDecimal(maxOrderPrice.toString());
            BigDecimal maxPriceRadio = value.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
            // 最大抵扣金额
            BigDecimal maxPointsMoney = gradePrice.multiply(maxPriceRadio).setScale(2, RoundingMode.HALF_UP);
            if (pointsMoney.compareTo(maxPointsMoney) > 0) {
                return maxPointsMoney;
            } else {
                return pointsMoney;

            }
        }
        return BigDecimal.ZERO;
    }

    /**
     * 设置订单积分抵扣价格
     *
     * @param pointsMoney
     * @param order
     * @param user
     * @param orderTotalPrice
     * @param pointMap
     * @return
     */
    private static BigDecimal setOrderPointsDiscount(BigDecimal pointsMoney, CheckOrderDto order, YoshopUserEntity user, BigDecimal orderTotalPrice, Map pointMap) {
        // 获取用户积分
        Integer userPoints = user.getPoints();
        // 设置积分抵扣价格
        // 积分抵扣比例 (设置1个积分可抵扣0.1元，则10积分可抵扣1元，100积分可抵扣10元)
        Object discount = pointMap.get("discount");
        Map map = JSON.parseObject(discount.toString(), Map.class);
        Object discountRatio = map.get("discount_ratio");
        // 满减金额
        Object fullOrderPrice = map.get("full_order_price");
        // 最大抵扣金额比例
        Object maxOrderPrice = map.get("max_money_ratio");

        // 计算抵扣金额
        if (userPoints > 0 && orderTotalPrice.compareTo(new BigDecimal(fullOrderPrice.toString())) > 0) {
            // 开启积分抵扣
            order.setIsAllowPoints(true);
            // 积分抵扣金额
            BigDecimal pointsMoneyNum = new BigDecimal(discountRatio.toString()).multiply(new BigDecimal(userPoints)).setScale(2, RoundingMode.HALF_UP);
            // 判断抵扣金额是否大于最大抵扣金额
            // 创建一个表示10%的BigDecimal对象，这里需要指定精度，因为0.1无法精确表示为二进制小数
            // 将值除以100
            BigDecimal value = new BigDecimal(maxOrderPrice.toString());
            BigDecimal maxPriceRadio = value.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
            // 最大抵扣金额
            BigDecimal maxPrice = orderTotalPrice.multiply(maxPriceRadio).setScale(2, RoundingMode.HALF_UP);

            if (pointsMoneyNum.compareTo(maxPrice) > 0) {
                // 设置最大抵扣金额
                order.setPointsMoney(String.valueOf(maxPrice));
                // 抵扣之后的金额 商品价格 - 积分抵扣价
                BigDecimal total_pay_price = orderTotalPrice.subtract(maxPrice);
                // 积分抵扣价
                order.setOrderPayPrice(String.valueOf(total_pay_price));
                order.setOrderPrice(String.valueOf(total_pay_price));
                pointsMoney = pointsMoney.add(maxPrice);
            } else {
                order.setPointsMoney(String.valueOf(pointsMoneyNum));
                // 抵扣之后的金额 商品价格 - 积分抵扣价
                BigDecimal total_pay_price = orderTotalPrice.subtract(pointsMoneyNum);
                // 积分抵扣价
                order.setOrderPayPrice(String.valueOf(total_pay_price));
                order.setOrderPrice(String.valueOf(total_pay_price));
                pointsMoney = pointsMoney.add(pointsMoneyNum);
            }
        }
        return pointsMoney;
    }

    /**
     * 查询购物车商品
     *
     * @param cartIds
     * @return
     */
    private List<YoshopCartEntity> queryGoodsByCartIds(String cartIds) {
        List<Integer> cartId = convertCommaSeparatedToIntegerList(cartIds);
        List<YoshopCartEntity> cart = cartDao.selectBatchIds(cartId);
        return cart;
    }

    /**
     * 将逗号分隔的字符串转换为Integer列表
     *
     * @param input
     * @return
     */
    public static List<Integer> convertCommaSeparatedToIntegerList(String input) {
        return Arrays.stream(input.split(","))
                .map(Integer::parseInt)
                .collect(Collectors.toList());
    }

    /**
     * 设置商品信息
     *
     * @param goodsEntity
     * @param goodsNum
     * @param cityId
     * @param userGrade
     * @param goodsSkuId
     * @param userPoints
     * @param pointMap
     * @return
     */
    public YoshopGoodsEntity setGoodsInfo(YoshopGoodsEntity goodsEntity, Integer goodsNum, String cityId, YoshopUserGradeEntity userGrade, String goodsSkuId, Integer userPoints, Map pointMap) {
        goodsEntity.setIsUserGrade(goodsEntity.getIsEnableGrade() == 1);
        // 商品原价
        BigDecimal goodsPrice = new BigDecimal(goodsEntity.getSkuInfo().getGoodsPrice());
        // 折扣支付价格
        BigDecimal goodsPayPrice = BigDecimal.ZERO;
        Integer isEnableGrade = goodsEntity.getIsEnableGrade();
        if (userGrade != null && isEnableGrade == 1) {
            // 会员价格
            goodsPayPrice = memberPrice(userGrade, goodsNum, goodsEntity, goodsPrice);
        } else {
            // 非会员价格
            goodsPayPrice = nonMemberPrice(goodsNum, goodsEntity, goodsPrice);
        }
        goodsEntity.setGoodsPrice(String.valueOf(goodsPrice));
        goodsEntity.setTotalPrice(String.valueOf(goodsPayPrice));
        goodsEntity.setTotalPayPrice(String.valueOf(goodsPayPrice));

        // 商品总数量
        goodsEntity.setTotalNum(goodsNum);
        // 商品支付总价(会员价)
        // BigDecimal totalPayPrice = gradePrice.add(expressPrice);
        // 商品价格（原价*97%=现价）
        goodsEntity.setGoodsSales(goodsEntity.getSalesActual());
        goodsEntity.setGoodsSkuId(goodsSkuId);

        // 2. 积分设置
        goodsEntity.setPointsNum(0);
        // 是否开启积分赠送(1开启 0关闭)
        Integer isShoppingGift = (Integer) pointMap.get("is_shopping_gift");
        // 是否开启积分赠送
        Integer isPointsGift = goodsEntity.getIsPointsGift();
        if (isShoppingGift == 1 && isPointsGift == 1) {
            // 设置积分赠送价格
            Integer pointsBonus = GetPointsBonus(pointMap, goodsPayPrice);
            goodsEntity.setPointsBonus(String.valueOf(pointsBonus));
            goodsEntity.setMaxPointsNum(String.valueOf(pointsBonus));
        }
        // 商品是否开启积分抵扣
        BigDecimal pointsMoney = pointsDeduction(goodsEntity, pointMap, goodsPayPrice, userPoints);
        if (pointsMoney.compareTo(BigDecimal.ZERO) > 0) {
            goodsEntity.setPointsMoney(String.valueOf(pointsMoney));
            goodsEntity.setPointsNum(pointsMoney.intValue());
        }

        // 商品运费
        YoshopDeliveryRuleEntity deliveryRule = feignstoreClient.queryDeliveryBigDecimalById(goodsEntity.getDeliveryId());
        //     判断是否在包邮区域内 isIntraRegion;
        String region = deliveryRule.getRegion();
        boolean intraRegion = isIntraRegion(region, Integer.valueOf(cityId));
        if (StringUtils.isEmpty(region) || !(intraRegion)) {
            goodsEntity.setIsIntraRegion(false);
            goodsEntity.setExpressPrice("0.00");
            return goodsEntity;
        }
        goodsEntity.setIsIntraRegion(true);
        // 运费价格
        BigDecimal totalFee = getGoodsExpressPrice(goodsEntity, goodsNum, deliveryRule);
        goodsEntity.setExpressPrice(String.valueOf(totalFee));
        return goodsEntity;
    }

    /**
     * 获取商品运费
     *
     * @param goodsEntity
     * @param goodsNum
     * @param deliveryRule
     * @return
     */
    private static BigDecimal getGoodsExpressPrice(YoshopGoodsEntity goodsEntity, Integer goodsNum, YoshopDeliveryRuleEntity deliveryRule) {
        Integer method = deliveryRule.getMethod();
        BigDecimal totalFee = BigDecimal.ZERO;

        Double goodsWeight = goodsEntity.getSkuInfo().getGoodsWeight();
        // 首件(个)/首重(Kg)
        Double first = deliveryRule.getFirst();
        // 首件(个)/首重(Kg) 价格
        BigDecimal firstFee = deliveryRule.getFirstFee();
        // 续件/续重
        Double additional = deliveryRule.getAdditional();
        // 续件/续重(价格)
        BigDecimal additionalFee = deliveryRule.getAdditionalFee();
        if (method == 10) {
            // 10按件数
            totalFee = firstFee.add(additionalFee.multiply(new BigDecimal(goodsNum - 1)));
        } else if (method == 20) {
            // 20按重量
            // 续重价格
            if (goodsWeight <= first) {
                totalFee = firstFee;
            } else {
                BigDecimal additionalWeightFee = BigDecimal.valueOf(Math.ceil((goodsWeight - first) / additional)).multiply(additionalFee);
                totalFee = firstFee.add(additionalWeightFee);
            }
        }
        return totalFee;
    }


}
